﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CommonLibrary
{
    public class MonitorMsgHelper
    {
        private CancellationTokenSource _cancelSource;
        private CancellationToken _cancelToken;
        private ManualResetEvent _resetEvent;
        private Task _monitorTask;
        private int _nextWaitSeconds = 1;
        private int _nextWaitMaxSeconds = 5;
        private int _breakTimes = 3;

        public void StartMonitor(int seconds, int maxSeconds, int breakTimes, Action AutoReTryAction, Func<bool> ValidationAction)
        {
            _nextWaitSeconds= seconds;
            _nextWaitMaxSeconds= maxSeconds;
            _breakTimes= breakTimes;
            if (_nextWaitSeconds <= 0 || _breakTimes <= 0) return;
            _cancelSource = new CancellationTokenSource();
            _cancelToken = _cancelSource.Token;
            _resetEvent = new ManualResetEvent(false);
            _monitorTask = Task.Run(() =>
             {
                 Console.WriteLine($"{DateTime.Now.ToString()}: Start Monitor Thread(Id: {Thread.CurrentThread.ManagedThreadId})");
                 while (!_cancelToken.IsCancellationRequested)
                 {
                     if (breakTimes > 0)
                     {
                         if (ValidationAction.Invoke())
                         {
                             Console.WriteLine($"{DateTime.Now.ToString()}: Monitor Receive True");
                             Console.WriteLine($"{DateTime.Now.ToString()}: Monitor Msg Finish");
                             break;
                         }
                         
                         Console.WriteLine($"{DateTime.Now.ToString()} Monitor Receive False");
                         
                         AutoReTryAction.Invoke();
                         
                         seconds += seconds;
                         if (seconds > _nextWaitMaxSeconds) seconds = _nextWaitMaxSeconds;

                         _resetEvent.WaitOne(seconds*1000);
                         _resetEvent.Reset();
                         
                         breakTimes--;
                     }
                     else
                     {
                         Console.WriteLine($"{DateTime.Now.ToString()}: Monitor Not Receive Msg in set times");
                     }
                 }
                 Console.WriteLine($"{DateTime.Now.ToString()}: Stop Monitor Success(Thread Id: {Thread.CurrentThread.ManagedThreadId})");
             }, _cancelToken);
        }

        public void StopMonitor()
        {
            _breakTimes = 0;
            _cancelSource?.Cancel();
            _resetEvent?.Set();
        }
    }
}
